#define F_CPU           8000000 
#define XTAL           8000000 
#ifndef F_CPU
#define F_CPU           8000000                   // processor clock frequency
//#warning kein F_CPU definiert
#endif


#include <stdlib.h>
#include <avr/io.h>
#include <avr/pgmspace.h>
#include <avr/interrupt.h>
#include <avr/sleep.h>
#include <util/delay.h>
#include "lcd.h"
#include "taster.h"
#include "ShiftRegister.h"
#include "irmp.h"
//#include "rc5.h"

#ifdef TIM1_COMPA_vect                                                      // ATtiny84
#define COMPA_VECT  TIM1_COMPA_vect
#else
#define COMPA_VECT  TIMER1_COMPA_vect                                       // ATmega
#endif



#define MUTEPORT    PORTA
#define MUTEDDR     DDRA
#define MUTEPIN     PINA6



uint8_t GlobalVolume = 1;
uint8_t GlobalInput = 1;
uint8_t Mute = 1;



int GlobalInPort[5] = {1, 2, 4, 8, 16}; 
int GlobalVolumeCurve[125] = {1,2,3,4,5,6,7,8,9,10,11,12,13,14,15,16,17,18,19,20,21,22,23,24,25,26,27,28,29,30,31,33,34,35,36,37,38,39,40,41,42,43,44,45,46,47,48,49,50,51,52,53,54,55,56,57,58,59,60,61,62,63,65,66,67,68,69,70,71,72,73,74,75,76,77,78,79,80,81,82,83,84,85,86,87,88,89,90,91,92,93,94,95,96,97,98,99,100,101,102,103,104,105,106,107,108,109,110,111,112,123,114,115,116,117,118,119,120,121,122,123,124,125,126,127}; // here one could have any desired volume curve

void UpdateDisplay( void );


int main(void)
{
  int Enc_delta_local_volume;  
  int Enc_delta_local_source;

  
  /* Set all Ports to output to avoid floating pins*/
  DDRA |= 0xFF;
  DDRB |= 0xFF;
  DDRC |= 0xFF;
  DDRD |= 0xFF;
  
  /*Set Port Function of Mute Relais*/
  MUTEDDR |= (1<<MUTEPIN);
  /*Start program with initial Mute to avoid for unwanted popping*/
  MUTEPORT |= (1<<MUTEPIN);
  
  /* initialize display, cursor off */
  lcd_init(LCD_DISP_ON);
  lcd_puts("LSQR4");
  
  /*Initialize the shift registers*/
  initShiftReg();
  SetVolumeAndInput(GlobalVolumeCurve[GlobalVolume], GlobalInPort[0]); /*Set volume and input to inital values*/
    
  /*Init port functions for rotary encoder*/
  DDRA &=~(1<<2);
  DDRA &=~(1<<3);
  PORTA |= (1<<2);
  PORTA |= (1<<3);
    
  DDRC &=~(1<<2);
  DDRC &=~(1<<3);
  PORTC |= (1<<2);
  PORTC |= (1<<3);
  
  encode_init(); /*initially read rotary encoder for proper starting conditions*/
    

  /*Init port functions for push-buttons*/
  KEY_DDR &= ~ALL_KEYS;                // configure key port for input
  KEY_PORT |= ALL_KEYS;                // and turn on pull up resistors
 
 /*set Timer for polling of push buttons and rotary encoder*/
 // TCCR0 = (1<<CS02)|(1<<CS00);         // divide by 1024
  //TCNT0 = (uint8_t)(int16_t)-(F_CPU  / 1024 * 1e-3 + 0.5);  // preload for 1ms
  //TIMSK |= 1<<TOIE0;                   // enable timer interrupt
 
 
 /*Init IR decoder software*/
    IRMP_DATA irmp_data;

    irmp_init();                                                            // initialize irmp
    timer1_init();                                                          // initialize timer1
                                                                
 
 

  sei(); /*enable globale interrupt*/
 
  for(;;){ // main loop - runs until eternity

    /*check if Mute Key was pressed*/
    if( get_key_press( 1<<KEYVOL )){
      if(Mute == 0){
        MUTEPORT &= ~(1<<MUTEPIN);
        lcd_clrscr();
        lcd_gotoxy(2,0);
        lcd_puts("Mute");
        Mute = 1;
      }else{
	MUTEPORT |= (1<<MUTEPIN);
        UpdateDisplay();
	Mute = 0;
      };
    };

    /*check if Volume was changed*/
    Enc_delta_local_volume =  encode_read_volume(); /*read encoder change*/
    if(Enc_delta_local_volume){
      if(GlobalVolume + Enc_delta_local_volume < 0){
	GlobalVolume = 0;
      }else{
        GlobalVolume += Enc_delta_local_volume; // update volume variable
        if(GlobalVolume > 124){
	  GlobalVolume = 124;
        };
      };
      UpdateDisplay();
      SetVolumeAndInput(GlobalVolumeCurve[GlobalVolume], GlobalInPort[GlobalInput-1]);
      Enc_delta_local_volume = 0;
    };
    
    /*check if Input selection was changed*/
    Enc_delta_local_source =  encode_read_source(); /*read encoder change*/
    if(Enc_delta_local_source){ /*if encoder has changed*/
      GlobalInput += Enc_delta_local_source;
      if(GlobalInput > 5){
	GlobalInput = 1;
      }
      if(GlobalInput < 1){
	GlobalInput = 5;
      }
      
      UpdateDisplay();
      SetVolumeAndInput(GlobalVolume, GlobalInPort[GlobalInput-1]);

      Enc_delta_local_source = 0;
    };
    
    if (irmp_get_data (&irmp_data))
        {
	  char buffer[10];
            // ir signal decoded, do something here...
            // irmp_data.protocol is the protocol, see irmp.h
            // irmp_data.address is the address/manufacturer code of ir sender
            // irmp_data.command is the command code
            // irmp_protocol_names[irmp_data.protocol] is the protocol name (if enabled, see irmpconfig.h)
	  lcd_clrscr();
	  lcd_gotoxy(0,0);
      lcd_puts("IR: ");
      itoa(  irmp_data.command, buffer, 10);
      lcd_puts(buffer);
      
      lcd_gotoxy(0,1);
      lcd_puts("Proc: ");
      itoa(  irmp_data.protocol, buffer, 10);
      lcd_puts(buffer);
        }
    
  }
  
  
}


void UpdateDisplay( void ){
  char buffer[10];
   lcd_clrscr();
      lcd_gotoxy(0,0);
      lcd_puts("In: ");
      itoa(  GlobalInput, buffer, 10);
      lcd_puts(buffer);
      
      lcd_gotoxy(0,1);
      lcd_puts("Vol: ");
      itoa( GlobalVolume, buffer, 10);
      lcd_puts(buffer);

  
}
 
ISR( COMPA_VECT )                                                             // Timer1 output compare A interrupt service routine, called every 1/15000 sec
{
  (void) irmp_ISR();                                                        // call irmp ISR
  (void) encoder_ISR ();
  // call other timer interrupt routines...
}

void
timer1_init (void)
{
                                                                      // ATmegaXX:
    OCR1A   =  (F_CPU / F_INTERRUPTS) - 1;                                  // compare value: 1/15000 of CPU frequency
    TCCR1B  = (1 << WGM12) | (1 << CS10);                                   // switch CTC Mode on, set prescaler to 1


#ifdef TIMSK1
    TIMSK1  = 1 << OCIE1A;                                                  // OCIE1A: Interrupt by timer compare
#else
    TIMSK   = 1 << OCIE1A;                                                  // OCIE1A: Interrupt by timer compare
#endif
}